/*
 * Copyright © 2004-2014 chenYuan. All rights reserved.
 * @Website:wwww.jspx.net
 * @Mail:39793751@qq.com
 * @author: chenYuan , 陈原
 * @License: Jspx.net Framework Code is open source (LGPL)，Jspx.net Framework 使用LGPL 开源授权协议发布。
 * @jvm:jdk1.6+  x86/amd64
 *
 */
package com.jspx.sober.util;

import com.jspx.boot.EnvFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.jspx.sober.TableModels;
import com.jspx.sober.config.SoberColumn;
import com.jspx.sober.config.SoberNexus;
import com.jspx.sober.config.SoberTable;
import com.jspx.sober.config.SoberCalcUnique;
import com.jspx.utils.*;
import com.jspx.sober.annotation.*;
import com.jspx.sober.sequences.SequencesDAO;
import com.jspx.sober.exception.ValidException;

import java.lang.reflect.Field;
import java.lang.annotation.Annotation;
import java.util.*;

/**
 * Created by IntelliJ IDEA.
 * User:chenYuan (mail:39793751@qq.com)
 * Date: 2007-2-5
 * Time: 23:49:08
 */
public abstract class AnnotationUtil {
    final static private Logger log = LoggerFactory.getLogger(AnnotationUtil.class.getName());
    final private static String KEY_SEQUENCE = "sequence";

    private AnnotationUtil() {

    }


    /**
     * @param object       自动生成ID
     * @param fieldName    字段名称
     * @param sequencesDAO 系列化DAO对象
     * @throws com.jspx.sober.exception.ValidException
     *          验证错误
     */
    public static void autoSetId(Object object, String fieldName, SequencesDAO sequencesDAO) throws ValidException {
        if (object == null || StringUtil.isNULL(fieldName)) return;
        try {
            Field field = ClassUtil.getDeclaredField(object.getClass(),fieldName);
            if (field==null) return;
            Id idf = field.getAnnotation(Id.class);
            if (idf == null || !idf.auto()) return;
            Object oldIdValue = BeanUtil.getProperty(object, field.getName());
            //长整类型
            if ((field.getType() == Long.class || field.getType() == long.class) && ObjectUtil.toInt(oldIdValue) == 0) {
                if (KEY_SEQUENCE.equalsIgnoreCase(idf.type()) || IDType.seq.equalsIgnoreCase(idf.type())) {
                    BeanUtil.setSimpleProperty(object, field.getName(), StringUtil.toInt(sequencesDAO.getNextKey(object.getClass().getName(), idf)));
                } else if (IDType.uid.equalsIgnoreCase(idf.type())) {
                    if (idf.length() >= 64)
                        BeanUtil.setSimpleProperty(object, field.getName(), Math.abs(UUID.randomUUID().getMostSignificantBits()));
                    else if (idf.length() >= 18) {
                        BeanUtil.setSimpleProperty(object, field.getName(), DateUtil.toString(new Date(), "yyMMddHHmmss") + RandomUtil.getRandom(6, false, true));
                    } else if (idf.length() > 10) {
                        BeanUtil.setSimpleProperty(object, field.getName(), System.currentTimeMillis() + RandomUtil.getRandom(3, false, true));
                    } else
                        BeanUtil.setSimpleProperty(object, field.getName(), RandomUtil.getRandomInt());
                } else {
                    BeanUtil.setSimpleProperty(object, field.getName(), RandomUtil.getRandomLong());
                }
            }
            //整数类型
            if ((field.getType() == Integer.class || field.getType() == int.class) && ObjectUtil.toInt(oldIdValue) == 0) {
                if (KEY_SEQUENCE.equalsIgnoreCase(idf.type()) || IDType.seq.equalsIgnoreCase(idf.type())) {
                    BeanUtil.setSimpleProperty(object, field.getName(), StringUtil.toInt(sequencesDAO.getNextKey(object.getClass().getName(), idf)));
                } else if (IDType.uid.equalsIgnoreCase(idf.type())) {
                    BeanUtil.setSimpleProperty(object, field.getName(), RandomUtil.getRandomInt());
                } else {
                    BeanUtil.setSimpleProperty(object, field.getName(), RandomUtil.getRandomInt());
                }
            }
            //字符串类型
            if (field.getType() == String.class && StringUtil.isNULL((String) oldIdValue)) {
                //字符串类型
                if (KEY_SEQUENCE.equalsIgnoreCase(idf.type()) || IDType.seq.equalsIgnoreCase(idf.type())) {
                    BeanUtil.setSimpleProperty(object, field.getName(), sequencesDAO.getNextKey(object.getClass().getName(), idf));
                } else if (IDType.uid.equalsIgnoreCase(idf.type())) {
                    BeanUtil.setSimpleProperty(object, field.getName(), UUID.randomUUID().toString());
                } else {
                    BeanUtil.setSimpleProperty(object, field.getName(), DateUtil.toString(new Date(), "yyMMddHHmmss") + RandomUtil.getRandom(3, false, true));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 得到数据库字段关系
     *
     * @param cls 类
     * @return List<SoberColumn>
     */
    public static List<SoberColumn> getColumnList(Class cls) {
        List<SoberColumn> soberColumns = new LinkedList<SoberColumn>();
        Field[] fields = ClassUtil.getDeclaredFields(cls);//字段
        for (Field field : fields) {
            Column column = field.getAnnotation(Column.class);
            if (column != null) {
                SoberColumn soberColumn = new SoberColumn();
                soberColumn.setName(field.getName());
                soberColumn.setClassType(field.getType());
                soberColumn.setCaption(column.caption());
                soberColumn.setOption(column.option());
                soberColumn.setLength(column.length());
                soberColumn.setDefaultValue(column.defaultValue());
                soberColumn.setNotNull(column.notNull());
                soberColumn.setDataType(column.dataType());
                soberColumn.setHidden(column.hidden());
                soberColumns.add(soberColumn);
                if (field.getType() == String.class && column.length() < 1) {
                    log.error("class " + cls.getName() + " field " + field.getName() + " not column length,没有定义字段长度");
                }
            }
        }
        return soberColumns;
    }

    /**
     * 得到映射关系
     *
     * @param cls 类
     * @return List<SoberNexus>
     */
    public static Map<String, SoberNexus> getSoberNexus(Class cls) {
        Map<String, SoberNexus> soberColumns = new LinkedHashMap<String, SoberNexus>();
        Field[] fields = ClassUtil.getDeclaredFields(cls);//字段
        for (Field field : fields) {
            Nexus nexus = field.getAnnotation(Nexus.class);
            if (nexus != null) {
                SoberNexus soberNexus = new SoberNexus();
                soberNexus.setMapping(nexus.mapping());
                soberNexus.setName(nexus.name());
                soberNexus.setTargetName(nexus.targetName());
                soberNexus.setTargetEntity(nexus.targetEntity());
                soberNexus.setOrderBy(nexus.orderBy());
                soberNexus.setDelete(nexus.delete());
                soberNexus.setUpdate(nexus.update());
                soberNexus.setSave(nexus.save());
                soberNexus.setChain(nexus.chain());
                soberNexus.setWhere(nexus.where());
                soberNexus.setLength(nexus.length());
                soberColumns.put(field.getName(), soberNexus);
            }
        }
        return soberColumns;
    }


    /**
     * 得到映射关系
     *
     * @param cls 类
     * @return List<SoberNexus>
     */
    public static Map<String, SoberCalcUnique> getSoberCalcUnique(Class cls) {
        Map<String, SoberCalcUnique> soberCalcUniques = new LinkedHashMap<String, SoberCalcUnique>();
        Field[] fields = ClassUtil.getDeclaredFields(cls);//字段
        for (Field field : fields) {
            CalcUnique calcUnique = field.getAnnotation(CalcUnique.class);
            if (calcUnique != null) {
                SoberCalcUnique soberCalcUnique = new SoberCalcUnique();
                soberCalcUnique.setName(field.getName());
                soberCalcUnique.setCaption(calcUnique.caption());
                soberCalcUnique.setSql(calcUnique.sql());
                soberCalcUnique.setValue(calcUnique.value());
                if (calcUnique.entity() == null) {
                    soberCalcUnique.setEntity(null);
                } else {
                    soberCalcUnique.setEntity(calcUnique.entity());
                }
                soberCalcUniques.put(field.getName(), soberCalcUnique);
            }
        }
        return soberCalcUniques;
    }

    /**
     * 得到映射关系中的表名
     *
     * @param cls 类
     * @return 表名
     */
    public static Table getTable(Class cls) {
        Annotation[] annotation = cls.getAnnotations();
        for (Annotation a : annotation) {
            if (a instanceof Table) {
                return (Table) a;
            }
        }
        return null;
    }

    /**
     *
     * @param cls 类
     * @return   得到的显示名称
     */
    public static String getTableCaption(Class cls) {
        Annotation[] annotation = cls.getAnnotations();
        for (Annotation anAnnotation : annotation) {
            if (anAnnotation instanceof Table) {
                return ((Table) anAnnotation).caption();
            }
        }
        return StringUtil.empty;
    }

    /**
     *
     * @param cls  class对象
     * @return   得到数据库的名
     */
    public static String getTableName(Class cls) {
        Annotation[] annotation = cls.getAnnotations();
        for (Annotation anAnnotation : annotation) {
            if (anAnnotation instanceof Table) {
                return ((Table) anAnnotation).name();
            }
        }
        return StringUtil.empty;
    }

    /**
     * 生成 SoberTable
     *
     * @param cls 实体对象
     * @return SoberTable
     */
    public static TableModels getSoberTable(Class cls)  {
        SoberTable soberTable = new SoberTable();
        soberTable.setEntity(cls);
        Table table = getTable(cls);
        if (table==null) return null;

        soberTable.setTableName(table.name());  //得到数据库表名
        soberTable.setTableCaption(table.caption());//表的别名
        soberTable.setUseCache(table.cache()); //是否使用cache 默认使用
        soberTable.setCacheName(table.cacheName()); //是否使用特殊的cache 容器
        soberTable.setCreate(table.create());
        soberTable.setColumns(getColumnList(cls)); //数据库字段
        soberTable.setCalcUniqueMap(getSoberCalcUnique(cls)); //单个计算
        soberTable.setNexusMap(getSoberNexus(cls)); //映射关系
        Field[] fields = ClassUtil.getDeclaredFields(cls);//字段
        //找到ID
        for (Field field : fields) {
            Id id = field.getAnnotation(Id.class);
            if (id != null) {
                soberTable.setPrimary(field.getName());
                soberTable.setAutoId(id.auto());
                soberTable.setIdType(id.type());
            }
        }
        return soberTable;
    }

    static public String getNexusOrderBy(Object obj,String orderBy) throws Exception
    {
        if (obj==null||orderBy==null) return StringUtil.empty;
        String[] orderByVar = StringUtil.getFreeMarkerVar(orderBy);
        if (!ArrayUtil.isEmpty(orderByVar))
        {
            Map<String,Object> valueMap = new HashMap<String, Object>();
            for (String varName:orderByVar)
            {
                valueMap.put(varName,BeanUtil.getProperty(obj,varName));
            }
            orderBy = EnvFactory.getPlaceholder().processTemplate(valueMap,orderBy);
        }
        return orderBy;
    }

    static public String getNexusTerm(Object obj,String term) throws Exception
    {
        if (obj==null||term==null) return StringUtil.empty;
        String[] termVar = StringUtil.getFreeMarkerVar(term);
        if (!ArrayUtil.isEmpty(termVar))
        {
            Map<String,Object> valueMap = new HashMap<String, Object>();
            for (String varName:termVar)
            {
                valueMap.put(varName,BeanUtil.getProperty(obj,varName));
            }
            term = EnvFactory.getPlaceholder().processTemplate(valueMap,term);
        }
        return term;
    }

    static public int getNexusLength(Object obj,String length,int defaultLength) throws Exception
    {
        if (obj==null||StringUtil.isNULL(length)) return defaultLength;

        String[] lengthVar = StringUtil.getFreeMarkerVar(length);
        if (!ArrayUtil.isEmpty(lengthVar))
        {
            Map<String,Object> valueMap = new HashMap<String, Object>();
            for (String varName:lengthVar)
            {
                valueMap.put(varName,BeanUtil.getProperty(obj,varName));
            }
            length = EnvFactory.getPlaceholder().processTemplate(valueMap,length);
        }
        int len = StringUtil.toInt(length);
        return len<=0?defaultLength:len;
    }
}